<template>
  <div class="wrap">
    <template>
      <div>
        <label class="label">{{$t('message.LandingGearFailureAnalysis.touchGroundLines')}}</label>
        <query-list
          v-model="params.touchGroundLines"
          :description="$t('message.LandingGearFailureAnalysis.touchGroundLines')"
          :active="params.queryListActiveMap.touchGroundLines"
          @switchQuery="switchQuery('touchGroundLines')"
          :tipMsg="$t('message.LandingGearFailureAnalysis.touchGroundLines')">
        </query-list>
      </div>
      <div>
        <label class="label">{{$t('message.LandingGearFailureAnalysis.wingSurfaces')}}</label>
        <query-list
          v-model="params.wingSurfaces"
          :description="$t('message.LandingGearFailureAnalysis.wingSurfaces')"
          :active="params.queryListActiveMap.wingSurfaces"
          @switchQuery="switchQuery('wingSurfaces')"
          :tipMsg="$t('message.LandingGearFailureAnalysis.wingSurfaces')">
        </query-list>
      </div>
      <div class="d-flex mt-2 align-items-center">
        <label class="el-form-item__label">{{$t('message.LandingGearFailureAnalysis.limitationDistance')}}：</label>
        <el-input v-model="params.limitationDistance"
                  type = "number"
                  step = "5"
                  min="0"/>
        <label class="label">mm</label>
      </div>
    </template>
    <!--    确认和关闭-->
    <div class="btn">
      <!--      <el-button-->
      <!--        type="primary"-->
      <!--        size="small"-->
      <!--        :disabled="false"-->
      <!--        @click="previewClick">-->
      <!--        {{ $t('message.WingTwistDesignDlg.preview') }}-->
      <!--      </el-button>-->
      <el-button
        type="primary"
        size="small"
        :disabled="params.touchGroundLines.length <=0 || params.wingSurfaces.length <=0 || params.limitationDistance <= 0.0001"
        @click="confirm">
        {{ $t('message.WingTwistDesignDlg.confirm') }}
      </el-button>
      <el-button
        size="small"
        @click="close">
        {{ $t('message.WingTwistDesignDlg.cancel') }}
      </el-button>
    </div>
  </div>
</template>

<script>
import DialogMixin from "../DialogMixin";
import {
  landingGearFailureAnalysisCommand
} from "../../../Command/LandingGearFailureAnalysisCommand";
import {ElementType, GeomType} from "../../../modeling/TypeDefine";
import {element} from "three/nodes";

export default {
  mixins: [DialogMixin],
  data() {
    return {
      params: {
        touchGroundLines:[],
        wingSurfaces:[],
        startAngle:0,
        endAngle:0,
        stepAngle:0,
        limitationDistance:1,
        queryListActiveMap:{
          touchGroundLines:1,
          wingSurfaces:0
        }
      },
      preview:false,
      thresholdValueMin:0.1,
    };
  },

  mounted() {
    landingGearFailureAnalysisCommand.init(400,300,300,() => {
      landingGearFailureAnalysisCommand.handlePickElement(data => {
        let edgeElements = [];
        let faceElements = [];
        if (data?.element?.length > 0) {
          let elementRes = data?.element;
          elementRes.forEach(subElement => {
            if (subElement?.element?.type === ElementType.DATUMLINE || subElement?.element?.type === ElementType.EDGE || subElement?.element?.type === ElementType.CURVE) {
              //if (subElement?.element?.params.type === GeomType.LINE)
              {
                let edgeElement = subElement?.element;
                //如果是在装配模式下，自己对名称和实例进行组合
                if(subElement.instance && subElement.instance.name){
                  edgeElement.name += "@" + subElement.instance.name;
                  edgeElement.instanceInfo = subElement.instance;
                }
                edgeElements.push(edgeElement);
              }
            }else if(subElement?.element?.type === ElementType.FACE || subElement?.element?.type === ElementType.SURFACE){
              //faceElements.push(subElement?.element);
              let faceElement = subElement?.element;
              //如果是在装配模式下，自己对名称和实例进行组合
              if(subElement.instance && subElement.instance.name){
                faceElement.name += "@" + subElement.instance.name;
                faceElement.instanceInfo = subElement.instance;
              }
              faceElements.push(faceElement);

            }
          })
        }

        if(this.params.queryListActiveMap.touchGroundLines && edgeElements.length > 0){
          this.params.touchGroundLines = [edgeElements[0]];
          this.params.queryListActiveMap.touchGroundLines = 0;
          this.params.queryListActiveMap.wingSurfaces = 1;
        }
        if(this.params.queryListActiveMap.wingSurfaces && faceElements.length > 0){
          let instanceAndSurfaceIds = [];
          this.params.wingSurfaces.forEach(surfaceData =>{
            let instanceAndSurfaceId = surfaceData.id;
            if(surfaceData.instanceInfo){
              instanceAndSurfaceId += "_" + surfaceData.instanceInfo.id;
            }
            instanceAndSurfaceIds.push(instanceAndSurfaceId)
          })

          //筛选同id的不进行添加,对sketchSelect的id进行区分
          faceElements.forEach(surfaceSelect => {
            let curInstanceAndSurfaceId = surfaceSelect.id;
            if(surfaceSelect.instanceInfo){
              curInstanceAndSurfaceId += "_" + surfaceSelect.instanceInfo.id;
            }

            if(surfaceSelect.id && !instanceAndSurfaceIds.includes(curInstanceAndSurfaceId)){
              this.params.wingSurfaces.push(surfaceSelect);
            }
          })
        }
      })
    })
  },

  methods: {
    changePluginContainerHeight() {
      landingGearFailureAnalysisCommand.changePluginContainerHeight({minWidth: this.$el.clientWidth, maxHeight: this.$el.clientHeight});
    },
    close(){
      landingGearFailureAnalysisCommand.closeActiveCmd();
    },
    confirm: function() {
      this.calculate();
    },

    calculate(){
      //从曲面获取到点集
      landingGearFailureAnalysisCommand.getFaceMeshPoints(this.params.wingSurfaces,pointsArray => {
        if(pointsArray.length === 0){
          return;
        }

        let points = [];
        for(let i = 0; i < pointsArray.length; i++){
          for(let j = 0; j < pointsArray[i].length / 3; j++){
            //数组处理成点
            let point = new THREE.Vector3(pointsArray[i][3 * j],pointsArray[i][3 * j + 1],pointsArray[i][3 * j + 2])
            //去重
            let isExist = false;
            points.forEach(curPoint => {
              if(curPoint.clone().sub(point).length() < 0.001){
                isExist = true;
              }
            })
            if(!isExist){
              points.push(point);
            }
          }
        }
        //线数组处理成点
        this.params.touchGroundLines[0].params.startPoint = new THREE.Vector3(this.params.touchGroundLines[0].params.startPoint[0],
          this.params.touchGroundLines[0].params.startPoint[1],
          this.params.touchGroundLines[0].params.startPoint[2]);
        this.params.touchGroundLines[0].params.endPoint = new THREE.Vector3(this.params.touchGroundLines[0].params.endPoint[0],
          this.params.touchGroundLines[0].params.endPoint[1],
          this.params.touchGroundLines[0].params.endPoint[2]);

        //进行矩阵变换，线和面都变换到全局坐标系下
        if(this.params.wingSurfaces[0].instanceInfo && this.params.wingSurfaces[0].instanceInfo.matrix){
          let surfaceMatrix = this.params.wingSurfaces[0].instanceInfo.matrix.elements;
          points = this.getWorldMatrixPoint(surfaceMatrix,points);
        }
        if(this.params.touchGroundLines[0].instanceInfo && this.params.touchGroundLines[0].instanceInfo.matrix){
          let lineMatrix = this.params.touchGroundLines[0].instanceInfo.matrix.elements;
          this.params.touchGroundLines[0].params.startPoint = this.getWorldMatrixPoint(lineMatrix,[this.params.touchGroundLines[0].params.startPoint])[0];
          this.params.touchGroundLines[0].params.endPoint = this.getWorldMatrixPoint(lineMatrix,[this.params.touchGroundLines[0].params.endPoint])[0];
        }

        //获取当前选取旋转线的方向和通过点
        let lineInfo = this.getLineInfo();

        //进行可计算性检查，如果本身数据有问题，可能导致陷入死循环无法计算出准确结果等问题
        // let checkCalculate = this.checkCalculatable(lineInfo,points);
        // if(!checkCalculate){
        //   return;
        // }

        //通过点集和选取的线，高效的获取通过线的面与点集的交点
        let tangentPoints = this.getTangentPoints(points,lineInfo.lineDir,lineInfo.linePoint);

        lineInfo.id = this.params.touchGroundLines[0].id;
        lineInfo.name = this.params.touchGroundLines[0].name;
        lineInfo.type = this.params.touchGroundLines[0].type;
        lineInfo.instanceId = this.params.touchGroundLines[0]?.instanceInfo?.id;

        //插件对得到的离散切点进行计算，通过离散切点再往外旋转，使用二分法进行求交
        let analysisInfo = {
          surfaceInfo:{
            surfaceId:this.params.wingSurfaces[0].id,
            instanceId:this.params.wingSurfaces[0]?.instanceInfo?.id,
          },
          lineInfo:lineInfo,
          tangentPoints:tangentPoints,
          thresholdValue:this.params.limitationDistance,
          instanceName:"失效分析",
        }

        //产品内部接口进行处理
        landingGearFailureAnalysisCommand.analysisCalculate(analysisInfo,res => {
          if(!this.preview){
            this.close();
          }
        })
      })
    },

    //点绕直线进行旋转指定角度时的位置，返回旋转后的点坐标
    getLineRevolvePoint(lineDir,linePoint,point,angle){
      //角度转换为弧度
      angle = angle * Math.PI / 180;

      //根据轴和角度设计旋转矩阵
      let rotateMatrix = new THREE.Matrix4();
      rotateMatrix.makeRotationAxis(lineDir,angle);

      //将旋转点进行位移到原点为基准的位置
      let directionToPoint = new THREE.Vector3().subVectors(point,linePoint);
      //应用旋转矩阵进行旋转
      directionToPoint.applyMatrix4(rotateMatrix);

      //旋转后的点加上基准
      let rotatedPoint = directionToPoint.add(linePoint);
      return rotatedPoint;
    },
    //获取直线的方向和点
    getLineInfo(){
      let lineDir = (this.params.touchGroundLines[0].params.endPoint.clone().sub(this.params.touchGroundLines[0].params.startPoint)).clone().normalize();

      let lineInfo = {
        lineDir:lineDir,
        linePoint:this.params.touchGroundLines[0].params.startPoint
      }
      return lineInfo;
    },

    //获取两个切点
    //曲面上的点需要确保应该在绕轴旋转平面的一侧，不能够让平面切割，否则即是产生干涉
    //至少应该有一个点与直线组成的平面，将其他所有点阻隔成在平面一侧
    getTangentPoints(points,lineDir,linePoint){
      let tangentPoints;

      //通过包围盒中心点与旋转轴组成的平面将所有点二分为两组点
      let boxCenter = this.getBoundingBoxCenter(points);


      //获取正向点组和反向点组
      let classPoints = this.classPointsByPlane(lineDir,linePoint,points,boxCenter,1);
      let classPositivePoints = classPoints.positivePoints;
      let classNegativePoints = classPoints.negativePoints;

      //如果获取到的一侧无点，则认为包围盒中心即切点
      if(classPositivePoints.length === 0 || classNegativePoints.length === 0){
        tangentPoints = {
          positivePoint:boxCenter,
          negativePoint:boxCenter,
        }
        return tangentPoints;
      }
      let positivePoint = boxCenter;
      let time = 0;
      //迭代正向点组获取切点
      while(true){
        positivePoint = this.getMostDistancePoint(lineDir,linePoint,positivePoint,classPositivePoints);

        classPositivePoints = this.classPointsByPlane(lineDir,linePoint,classPositivePoints,positivePoint,1).positivePoints;

        if(classPositivePoints.length === 0){
          break;
        }else if(classPositivePoints.length === 1){
          positivePoint = classPositivePoints[0];
          break;
        }
        time ++;
        if(time > 100000){
          break;
        }
      }

      time = 0;
      let negativePoint = boxCenter;
      //迭代正向点组获取切点
      while(true){
        //negativePoint = this.getMostDistancePoint(lineDir,linePoint,negativePoint,classNegativePoints);
        negativePoint = this.getMostDistancePoint(lineDir,linePoint,negativePoint,classNegativePoints);

        classNegativePoints = this.classPointsByPlane(lineDir,linePoint,classNegativePoints,negativePoint,-1).negativePoints;

        if(classNegativePoints.length === 0){
          break;
        }else if(classNegativePoints.length === 1){
          negativePoint = classNegativePoints[0];
          break;
        }

        time ++;
        if(time > 100000){
          break;
        }
      }

      tangentPoints = {
        positivePoint:positivePoint,
        negativePoint:negativePoint,
      }
      return tangentPoints;
    },

    //通过一个点和方向组成的直线和一个不在直线上的点组成的平面，返回一个ThreeJS的平面
    getPlaneByLineAndPoint(lineDir,linePoint,point){
      //平面上的两个点先确定另一条平面上的方向
      let lineDir2 = point.clone().sub(linePoint);
      lineDir2.normalize();
      lineDir.normalize();
      //判断如果两个方向为同一方向，不能确定一个平面,正向反向都不可以
      if(lineDir2.clone().sub(lineDir).length() < 0.001 || lineDir2.clone().add(lineDir).length() < 0.001){
        return null;
      }

      //叉乘获取平面的法向
      let dirNormal = new THREE.Vector3().crossVectors(lineDir,lineDir2);
      dirNormal.normalize();

      //原点到平面上任意一点的向量，在平面法向上的投影距离，即当前平面到原点的距离
      let distancePlane = linePoint.dot(dirNormal);
      let newPlane = new THREE.Plane(dirNormal,distancePlane);
      return newPlane;
    },

    //通过轴线和一个点的平面将一组点分为两侧的点
    //lineDir 线方向
    //linePoint 线上一点
    //points 所有点集
    //planePoint 平面过点
    //dirCoefficient 方向系数，1为正向，-1为反向
    classPointsByPlane(lineDir,linePoint,points,planePoint,dirCoefficient){
      let points1 = [];
      let points2 = [];

      //通过包围盒中心与旋转轴组成的平面
      //let plane = this.getPlaneByLineAndPoint(lineDir,linePoint,planePoint);

      //包围盒中心平面的法向
      //let planeNormal = plane.normal;
      let planeNormal = this.getNormalByPlane(planePoint,linePoint,lineDir);
      //平面起始点到某点的向量，点乘平面的法向量，得到的值大于0为一组，小于0为一组
      points.forEach(point =>{
        //let dirOriginToPoint = point.clone().sub(linePoint);
        let dirOriginToPoint = point.clone().sub(planePoint);
        //let dotValue = dirOriginToPoint.dot(planeNormal) * dirCoefficient;
        let dotValue = dirOriginToPoint.dot(planeNormal);
        if(dotValue > 0){
          points1.push(point);
        }else if(dotValue < 0){
          points2.push(point);
        }
      })

      //查找的正向点与反向点
      let classPoints = {
        positivePoints:points1,
        negativePoints:points2,
      }

      return classPoints;
    },

    //获取一组点中到平面距离最远的点
    getMostDistancePoint(lineDir,linePoint,planePoint,points){
      let mostDistance = -1000000;
      let mostDistancePoint = new THREE.Vector3();
      points.forEach(point => {
        //let disPointToPlane = Math.abs(plane.distanceToPoint(point));
        let disPointToPlane = this.getDistancePointToPlane(point,planePoint,lineDir);
        if(disPointToPlane > mostDistance){
          mostDistancePoint = point;
          mostDistance = disPointToPlane;
        }
      })
      return mostDistancePoint;
    },
    //点到点与法线组成的平面的距离
    getDistancePointToPlane(point,planePoint,planeDir){
      //点到平面的距离
      let pointToPlanePoint = planePoint.clone().sub(point);
      let disPointToPlane = Math.abs(pointToPlanePoint.clone().dot(planeDir)) / (planeDir.length());
      return disPointToPlane;
    },
    //获取一个平面的法线，该平面由一条线和一个点组成，线由点与方向构成
    getNormalByPlane(pointOnPlane,linePoint,lineDir){
      let pointOnPlaneToLinePoint = linePoint.clone().sub(pointOnPlane);
      let normalize1 = pointOnPlaneToLinePoint.clone().normalize();
      let normalize2 = lineDir.clone().normalize();
      let dotValue = normalize1.clone().dot(normalize2);

      //进行非同向异向判断
      let planeNormal = null;
      if(Math.abs(Math.abs(dotValue) - 1) > 0.001){
        planeNormal = new THREE.Vector3().crossVectors(normalize1,normalize2);
        planeNormal.normalize();
      }
        return planeNormal;
    },
    //根据输入的矩阵，进行运算
    getWorldMatrixPoint(matrixArray,points){
      if(!matrixArray || matrixArray.length !== 16){
        return points;
      }

      //判断矩阵数组是否是单位矩阵
      if(matrixArray[0] === 1 && matrixArray[1] === 0 && matrixArray[2] === 0 && matrixArray[3] === 0 &&
        matrixArray[4] === 0 && matrixArray[5] === 1 && matrixArray[6] === 0 && matrixArray[7] === 0 &&
        matrixArray[8] === 0 && matrixArray[9] === 0 && matrixArray[10] === 1 && matrixArray[11] === 0 &&
        matrixArray[12] === 0 && matrixArray[13] === 0 && matrixArray[14] === 0 && matrixArray[15] === 1){
        return points;
      }

      let matrix4 = new THREE.Matrix4(matrixArray[0],matrixArray[4],matrixArray[8],matrixArray[12],
        matrixArray[1],matrixArray[5],matrixArray[9],matrixArray[13],
        matrixArray[2],matrixArray[6],matrixArray[10],matrixArray[14],
        matrixArray[3],matrixArray[7],matrixArray[11],matrixArray[15]
      );

      let newPoints = [];
      points.forEach(point => {
        let newPoint = point.clone().applyMatrix4(matrix4);
        newPoints.push(newPoint);
      })

      return newPoints;
    },
    checkCalculatable(lineInfo,points){
      //首先保证





    },
    //获取包围盒中心
    getBoundingBoxCenter(points){
      let box = new THREE.Box3().setFromPoints(points);
      let center = new THREE.Vector3((box.max.x + box.min.x) / 2 ,(box.max.y + box.min.y) / 2 ,(box.max.z + box.min.z) / 2 )
      return center;
    },
    //激活的选取框
    switchQuery(name) {
      for (const key in this.params.queryListActiveMap) {
        if (key === name){
          this.params.queryListActiveMap[key] = 1;
        }else{
          this.params.queryListActiveMap[key] = 0;
        }
      }
    },


  },

  watch: {

  },
};
</script>
<style scoped>
.wrap {
    font-size: 12px;
}
.result-item .angle-icon {
    font-weight: bold;
    padding: 0 2px;
}
.dialog-query-list .move-buttons {
    margin-right: 35px;
}
</style>
